/**
 * 		User.java
 *  Adrián E. Córdoba 		04/05/2014
 */
package ar.com.adriancordoba.app.enterprise.rosc.model.entities;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.jboss.logging.Logger;

import ar.com.adriancordoba.app.enterprise.rosc.model.connections.ConnectionsManager;

/**
 * 
 * @author Adrián E. Córdoba
 */
public class User implements Serializable {
	private int id;
	private String username;
	private String firstName;
	private String middleName;
	private String lastName;
	private boolean active;
	private Role role;

	private static final long serialVersionUID = 1L;
	private static Logger logger = Logger.getLogger(User.class);

	/**
	 * @param id
	 * @param username
	 * @param firstName
	 * @param middleName
	 * @param lastName
	 * @param role
	 */
	public User(int id, String username, String firstName, String middleName,
			String lastName, Role role) {
		this.id = id;
		this.username = username;
		this.firstName = firstName;
		this.middleName = middleName;
		this.lastName = lastName;
		this.role = role;
	}

	/**
	 * 
	 */
	public User() {
	}

	public static User getUser(String username, String password) {
		User user = null;
		Role role = null;

		Encrypter encrypter = new Encrypter();
		String encryptedPassword = encrypter.encrypt(password);

		Connection connection = ConnectionsManager.getConnection();
		CallableStatement statement = null;
		ResultSet resultSet = null;
		if (connection != null) {
			try {
				statement = connection
						.prepareCall("{call getUserByUsernameAndPassword(?, ?)}");
				statement.setString(1, username);
				statement.setString(2, encryptedPassword);
				resultSet = statement.executeQuery();
				while (resultSet.next()) {
					if (resultSet.isFirst()) {
						user = new User();
						user.setId(resultSet.getInt("person_id"));
						logger.debug("User (user_id = " + user.getId()
								+ ") was obtained from database.");
						user.setFirstName(resultSet.getString("first_name"));
						user.setMiddleName(resultSet.getString("middle_name"));
						user.setLastName(resultSet.getString("last_name"));
						user.setUsername(resultSet.getString("user_name"));
						user.setActive(resultSet.getBoolean("active"));

						role = new Role();
						role.setName(resultSet.getString("role_name"));
						user.setRole(role);
					}
					if (role != null) {
						Permission permission = new Permission();
						permission.setModule(resultSet.getString("module"));
						permission.setView(resultSet.getBoolean("view"));
						permission.setCreate(resultSet.getBoolean("create"));
						permission.setModify(resultSet.getBoolean("modify"));
						permission.setDelete(resultSet.getBoolean("delete"));
						role.addPermission(permission);
					}
				}
			} catch (SQLException e) {
				logger.error("Cannot get callable statement from connection. - "
						+ e);
			} finally {
				try {
					if (resultSet != null)
						resultSet.close();
					if (statement != null)
						statement.close();
					connection.close();
				} catch (SQLException e) {
					logger.error("Cannot close database connection, statement or result set.");
				}
			}
		} else {
			logger.error("Cannot get authenticated user - No database connection.");
		}
		return user;
	}

	/**
	 * @author Adrián E. Córdoba
	 */
	private static class Encrypter {
		private MessageDigest messageDigest;

		/**
		 * Construct an encrypter wtih SHA-256 algorithm.
		 */
		public Encrypter() {
			try {
				messageDigest = MessageDigest.getInstance("SHA-256");
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			}
		}

		/**
		 * Encrypt a string.
		 * 
		 * @param text Text to encrypt.
		 * @return Encrypted text.
		 */
		public String encrypt(String text) {
			String encryptedText = null;
			if ((messageDigest != null) && (text != null)) {
				byte[] textArray = text.getBytes();
				textArray = messageDigest.digest(textArray);
				encryptedText = byteArrayToHexString(textArray);
			}
			return encryptedText;
		}

		/**
		 * Get a string from a byte array.
		 * 
		 * @param byteArray A byte array.
		 * @return A string obtained.
		 */
		private String byteArrayToHexString(byte[] byteArray) {
			StringBuffer sb = new StringBuffer(byteArray.length * 2);
			for (int i = 0; i < byteArray.length; i++) {
				int v = byteArray[i] & 0xff;
				if (v < 16) {
					sb.append('0');
				}
				sb.append(Integer.toHexString(v));
			}
			return sb.toString().toUpperCase();
		}
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the middleName
	 */
	public String getMiddleName() {
		return middleName;
	}

	/**
	 * @param middleName the middleName to set
	 */
	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	/**
	 * @return the active
	 */
	public boolean isActive() {
		return active;
	}

	/**
	 * @param active the active to set
	 */
	public void setActive(boolean active) {
		this.active = active;
	}

	/**
	 * @return the role
	 */
	public Role getRole() {
		return role;
	}

	/**
	 * @param role the role to set
	 */
	public void setRole(Role role) {
		this.role = role;
	}
}
